﻿using System;
using System.Collections.Generic;
using System.IO;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.GeometriesGraph
{
	public class DirectedEdgeStar : EdgeEndStar
	{
		public override void Insert(EdgeEnd ee)
		{
			DirectedEdge directedEdge = (DirectedEdge)ee;
			base.InsertEdgeEnd(directedEdge, directedEdge);
		}

		public Label Label
		{
			get
			{
				return this._label;
			}
		}

		public int GetOutgoingDegree()
		{
			int num = 0;
			IEnumerator<EdgeEnd> enumerator = base.Edges.GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					if (((DirectedEdge)enumerator.Current).IsInResult)
					{
						num++;
					}
				}
			}
			return num;
		}

		public int GetOutgoingDegree(EdgeRing er)
		{
			int num = 0;
			IEnumerator<EdgeEnd> enumerator = base.Edges.GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					if (((DirectedEdge)enumerator.Current).EdgeRing == er)
					{
						num++;
					}
				}
			}
			return num;
		}

		public DirectedEdge GetRightmostEdge()
		{
			IList<EdgeEnd> edges = base.Edges;
			int count = edges.Count;
			if (count < 1)
			{
				return null;
			}
			DirectedEdge directedEdge = (DirectedEdge)edges[0];
			if (count == 1)
			{
				return directedEdge;
			}
			DirectedEdge directedEdge2 = (DirectedEdge)edges[count - 1];
			int quadrant = directedEdge.Quadrant;
			int quadrant2 = directedEdge2.Quadrant;
			if (QuadrantOp.IsNorthern(quadrant) && QuadrantOp.IsNorthern(quadrant2))
			{
				return directedEdge;
			}
			if (!QuadrantOp.IsNorthern(quadrant) && !QuadrantOp.IsNorthern(quadrant2))
			{
				return directedEdge2;
			}
			if (directedEdge.Dy != 0.0)
			{
				return directedEdge;
			}
			if (directedEdge2.Dy != 0.0)
			{
				return directedEdge2;
			}
			Assert.ShouldNeverReachHere("found two horizontal edges incident on node");
			return null;
		}

		public override void ComputeLabelling(GeometryGraph[] geom)
		{
			base.ComputeLabelling(geom);
			this._label = new Label(Location.Null);
			foreach (EdgeEnd edgeEnd in this)
			{
				Label label = edgeEnd.Edge.Label;
				for (int i = 0; i < 2; i++)
				{
					Location location = label.GetLocation(i);
					if (location == Location.Interior || location == Location.Boundary)
					{
						this._label.SetLocation(i, Location.Interior);
					}
				}
			}
		}

		public void MergeSymLabels()
		{
			foreach (EdgeEnd edgeEnd in base.Edges)
			{
				DirectedEdge directedEdge = (DirectedEdge)edgeEnd;
				directedEdge.Label.Merge(directedEdge.Sym.Label);
			}
		}

		public void UpdateLabelling(Label nodeLabel)
		{
			foreach (EdgeEnd edgeEnd in base.Edges)
			{
				Label label = ((DirectedEdge)edgeEnd).Label;
				label.SetAllLocationsIfNull(0, nodeLabel.GetLocation(0));
				label.SetAllLocationsIfNull(1, nodeLabel.GetLocation(1));
			}
		}

		private IList<DirectedEdge> GetResultAreaEdges()
		{
			if (this._resultAreaEdgeList != null)
			{
				return this._resultAreaEdgeList;
			}
			this._resultAreaEdgeList = new List<DirectedEdge>();
			foreach (EdgeEnd edgeEnd in base.Edges)
			{
				DirectedEdge directedEdge = (DirectedEdge)edgeEnd;
				if (directedEdge.IsInResult || directedEdge.Sym.IsInResult)
				{
					this._resultAreaEdgeList.Add(directedEdge);
				}
			}
			return this._resultAreaEdgeList;
		}

		public void LinkResultDirectedEdges()
		{
			this.GetResultAreaEdges();
			DirectedEdge directedEdge = null;
			DirectedEdge directedEdge2 = null;
			int num = 1;
			for (int i = 0; i < this._resultAreaEdgeList.Count; i++)
			{
				DirectedEdge directedEdge3 = this._resultAreaEdgeList[i];
				DirectedEdge sym = directedEdge3.Sym;
				if (directedEdge3.Label.IsArea())
				{
					if (directedEdge == null && directedEdge3.IsInResult)
					{
						directedEdge = directedEdge3;
					}
					if (num != 1)
					{
						if (num == 2)
						{
							if (directedEdge3.IsInResult)
							{
								directedEdge2.Next = directedEdge3;
								num = 1;
							}
						}
					}
					else if (sym.IsInResult)
					{
						directedEdge2 = sym;
						num = 2;
					}
				}
			}
			if (num == 2)
			{
				if (directedEdge == null)
				{
					throw new TopologyException("no outgoing dirEdge found", base.Coordinate);
				}
				Assert.IsTrue(directedEdge.IsInResult, "unable to link last incoming dirEdge");
				directedEdge2.Next = directedEdge;
			}
		}

		public void LinkMinimalDirectedEdges(EdgeRing er)
		{
			DirectedEdge directedEdge = null;
			DirectedEdge directedEdge2 = null;
			int num = 1;
			for (int i = this._resultAreaEdgeList.Count - 1; i >= 0; i--)
			{
				DirectedEdge directedEdge3 = this._resultAreaEdgeList[i];
				DirectedEdge sym = directedEdge3.Sym;
				if (directedEdge == null && directedEdge3.EdgeRing == er)
				{
					directedEdge = directedEdge3;
				}
				if (num != 1)
				{
					if (num == 2)
					{
						if (directedEdge3.EdgeRing == er)
						{
							directedEdge2.NextMin = directedEdge3;
							num = 1;
						}
					}
				}
				else if (sym.EdgeRing == er)
				{
					directedEdge2 = sym;
					num = 2;
				}
			}
			if (num == 2)
			{
				Assert.IsTrue(directedEdge != null, "found null for first outgoing dirEdge");
				Assert.IsTrue(directedEdge.EdgeRing == er, "unable to link last incoming dirEdge");
				directedEdge2.NextMin = directedEdge;
			}
		}

		public void LinkAllDirectedEdges()
		{
			IList<EdgeEnd> edges = base.Edges;
			DirectedEdge directedEdge = null;
			DirectedEdge directedEdge2 = null;
			for (int i = this.edgeList.Count - 1; i >= 0; i--)
			{
				DirectedEdge directedEdge3 = (DirectedEdge)this.edgeList[i];
				DirectedEdge sym = directedEdge3.Sym;
				if (directedEdge2 == null)
				{
					directedEdge2 = sym;
				}
				if (directedEdge != null)
				{
					sym.Next = directedEdge;
				}
				directedEdge = directedEdge3;
			}
			directedEdge2.Next = directedEdge;
		}

		public void FindCoveredLineEdges()
		{
			Location location = Location.Null;
			foreach (EdgeEnd edgeEnd in base.Edges)
			{
				DirectedEdge directedEdge = (DirectedEdge)edgeEnd;
				DirectedEdge sym = directedEdge.Sym;
				if (!directedEdge.IsLineEdge)
				{
					if (directedEdge.IsInResult)
					{
						location = Location.Interior;
						break;
					}
					if (sym.IsInResult)
					{
						location = Location.Exterior;
						break;
					}
				}
			}
			if (location == Location.Null)
			{
				return;
			}
			Location location2 = location;
			foreach (EdgeEnd edgeEnd2 in base.Edges)
			{
				DirectedEdge directedEdge2 = (DirectedEdge)edgeEnd2;
				DirectedEdge sym2 = directedEdge2.Sym;
				if (directedEdge2.IsLineEdge)
				{
					directedEdge2.Edge.Covered = (location2 == Location.Interior);
				}
				else
				{
					if (directedEdge2.IsInResult)
					{
						location2 = Location.Exterior;
					}
					if (sym2.IsInResult)
					{
						location2 = Location.Interior;
					}
				}
			}
		}

		public void ComputeDepths(DirectedEdge de)
		{
			int num = base.FindIndex(de);
			int depth = de.GetDepth(Positions.Left);
			int depth2 = de.GetDepth(Positions.Right);
			int startDepth = this.ComputeDepths(num + 1, this.edgeList.Count, depth);
			if (this.ComputeDepths(0, num, startDepth) != depth2)
			{
				throw new TopologyException("depth mismatch at " + de.Coordinate);
			}
		}

		private int ComputeDepths(int startIndex, int endIndex, int startDepth)
		{
			int num = startDepth;
			for (int i = startIndex; i < endIndex; i++)
			{
				DirectedEdge directedEdge = (DirectedEdge)this.edgeList[i];
				directedEdge.SetEdgeDepths(Positions.Right, num);
				num = directedEdge.GetDepth(Positions.Left);
			}
			return num;
		}

		public override void Write(StreamWriter outstream)
		{
			foreach (EdgeEnd edgeEnd in base.Edges)
			{
				DirectedEdge directedEdge = (DirectedEdge)edgeEnd;
				outstream.Write("out ");
				directedEdge.Write(outstream);
				outstream.WriteLine();
				outstream.Write("in ");
				directedEdge.Sym.Write(outstream);
				outstream.WriteLine();
			}
		}

		private IList<DirectedEdge> _resultAreaEdgeList;

		private Label _label;

		private const int ScanningForIncoming = 1;

		private const int LinkingToOutgoing = 2;
	}
}
